﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;
using MageDefender.ParticleEngine;

namespace MageDefender.Scenes
{
    public class LevelScene : Microsoft.Xna.Framework.DrawableGameComponent
    {
        Effect effectPostOutlineSilhouettes;
        Effect effectPostOutlineParticles;
        Effect effectFindEdges;

        RenderTarget2D renderTargetMainScene;
        Texture2D textureMainScene;

        RenderTarget2D renderTargetStrippedScene;
        Texture2D textureStrippedScene;

        RenderTarget2D renderTargetSilhouettesScene;
        Texture2D textureSilhouettesScene;

        RenderTarget2D renderTargetFinalCompScene;
        Texture2D textureFinalCompScene;

        RenderTarget2D renderTargetParticlesOnlyScene;
        Texture2D textureParticlesOnlyScene;

        List<Texture2D> spellIcons;

        AudioEngine engine;
        SoundBank soundBank;
        WaveBank waveBank;
        Cue shootCue;

        Texture2D waveCompleteTexture;
        Texture2D levelUpNotifier;
        HelperComponents.FrameRateCounter fpsCounterComponent;

        ParticleSystem fireBallParticles;
        ParticleSystem slowEnemyParticles;
        ParticleSystem poisonEnemyParticles;
        ParticleSystem magicMissilePartilces;
        ParticleSystem dirtPartilces;

        float pressTimerPrimary = 100;
        float pressTimerSecondary = 100;
        float pressTimerSpellBrowse = 100;
        float drinkPotionTimer = 100;

        bool isWaveFinished;

        public bool IsWaveFinished
        {
            get { return isWaveFinished; }
            set { isWaveFinished = value; }
        }

        public GameObjects.Player Player
        {
            get { return m_Player; }
            set { m_Player = value; }
        }

        public GameObjects.Fort Castle
        {
            get { return m_Castle; }
            set { m_Castle = value; }
        }

        float finishTimer = 3000;
        SpriteBatch spriteBatch;
        SpriteFont m_font;
        SpriteFont m_fontLarge;

        GameObjects.Scenery m_Scenery;
        GameObjects.Player m_Player;
        GameObjects.SpellHandler m_SpellHandler;
        GameObjects.EnemyHandler m_EnemyHandler;
        GameClasses.Camera m_Camera;
        GameObjects.Fort m_Castle;

        float cameraZoom = 0.8f;

        Texture2D mdUITexture;
        Texture2D mdUIBackTexture;
        Texture2D bossUITexture;
        Texture2D blankTexture;

        /// <summary>
        /// Starts a new wave. This is where the level is designed also. Just add the different kinds of enemies you want to spawn
        /// randomly and thats it!
        /// </summary>
        public void StartNewWave()
        {

            finishTimer = 3000;

            isWaveFinished = false;
            pressTimerPrimary = 500;
            pressTimerSecondary = 500;
            pressTimerSpellBrowse = 500;
            drinkPotionTimer = 500;

            m_Player.Mana = m_Player.MaxMana;
            m_Player.Health = m_Player.MaxHealth;

            m_Castle.NextWave();

            m_EnemyHandler.SpawnEnemyTypes.Clear();

            switch(m_Castle.TheCastle.Wave)
            {
                case 1:
                    {
                        m_EnemyHandler.SpawnEnemyTypes.Add(GameObjects.EnemyHandler.Enemies.Slime);
                        break;
                    }
                case 2:
                    {
                        m_EnemyHandler.SpawnEnemyTypes.Add(GameObjects.EnemyHandler.Enemies.Slime2);
                        break;
                    }
                case 3:
                    {
                        m_EnemyHandler.SpawnEnemyTypes.Add(GameObjects.EnemyHandler.Enemies.Slime);
                        m_EnemyHandler.SpawnEnemyTypes.Add(GameObjects.EnemyHandler.Enemies.Slime2);
                        break;
                    }
                case 4:
                    {
                        m_EnemyHandler.SpawnEnemyTypes.Add(GameObjects.EnemyHandler.Enemies.Slime);
                        m_EnemyHandler.SpawnEnemyTypes.Add(GameObjects.EnemyHandler.Enemies.Slime2);
                        m_EnemyHandler.SpawnEnemyTypes.Add(GameObjects.EnemyHandler.Enemies.Slime3);
                        m_EnemyHandler.SpawnEnemyTypes.Add(GameObjects.EnemyHandler.Enemies.Slime4);
                        break;
                    }
                case 5:
                    {
                        m_EnemyHandler.SpawnEnemyTypes.Add(GameObjects.EnemyHandler.Enemies.Boss);
                        break;
                    }
                case 6:
                    {
                        m_EnemyHandler.SpawnEnemyTypes.Add(GameObjects.EnemyHandler.Enemies.Ghost);
                        break;
                    }
                case 7:
                    {
                        m_EnemyHandler.SpawnEnemyTypes.Add(GameObjects.EnemyHandler.Enemies.Skeleton);
                        break;
                    }
                case 8:
                    {
                        m_EnemyHandler.SpawnEnemyTypes.Add(GameObjects.EnemyHandler.Enemies.Zombie);
                        break;
                    }
                default:
                    {
                        m_EnemyHandler.SpawnEnemyTypes.Add(GameObjects.EnemyHandler.Enemies.Slime);
                        m_EnemyHandler.SpawnEnemyTypes.Add(GameObjects.EnemyHandler.Enemies.Slime2);
                        m_EnemyHandler.SpawnEnemyTypes.Add(GameObjects.EnemyHandler.Enemies.Slime3);
                        m_EnemyHandler.SpawnEnemyTypes.Add(GameObjects.EnemyHandler.Enemies.Ghost);
                        m_EnemyHandler.SpawnEnemyTypes.Add(GameObjects.EnemyHandler.Enemies.Zombie);
                        m_EnemyHandler.SpawnEnemyTypes.Add(GameObjects.EnemyHandler.Enemies.Skeleton);
                        break;
                    }
            }

            m_EnemyHandler.SpawnNewEnemy = 2000;
        }

        public bool TheWaveWasABoss()
        {
            return m_Castle.TheCastle.IsCurrentWaveABoss;
        }

        public void ResetLevel()
        {
            finishTimer = 3000;

            m_SpellHandler.SelectedSpellIndex = 0;

            m_Castle.TheCastle.Hp = 10000;
            m_Castle.TheCastle.Level = 2;
            m_Castle.TheCastle.Wave = 0;
            m_Castle.TheCastle.EnemiesInCurrentWave = 20;
            m_Castle.TheCastle.Defence = 1;
            m_Castle.TheCastle.IsCurrentWaveABoss = false;

            m_Player.Ap = 0;

            m_Player.ManaPotions = 5;
            m_Player.HealthPotions = 5;

            m_Player.Strength = 10;
            m_Player.Constitution = 10;
            m_Player.Intelligence = 10;
            m_Player.Wisdom = 10;
            m_Player.Agility = 10;

            m_Player.Mana = 100;
            m_Player.Health = 100;
            m_Player.Gold = 0;
            m_Player.XpToNextLevel = 0;
            m_Player.Level = 0;
            m_Player.LevelUp();

            m_SpellHandler.ClearSpellList();
            m_EnemyHandler.ClearEnemies();
            m_SpellHandler.LearnedSpells.Clear();
            m_SpellHandler.LearnSpell(global::MageDefender.GameObjects.SpellHandler.Spells.Fireball);
            m_EnemyHandler.SpawnEnemyTypes.Clear();

            StartNewWave();
        }

        public bool IsGameOver()
        {
            if (m_Player.Health <= 0 || m_Castle.TheCastle.Hp <= 0)
            {
                ResetLevel();
                return true;
            }

            return false;
        }

        public LevelScene(Game game)
            : base(game)
        {
            engine = new AudioEngine("Content\\music.xgs");
            soundBank = new SoundBank(engine, "Content\\SoundBank.xsb");
            waveBank = new WaveBank(engine, "Content\\WaveBank.xwb");

            shootCue = soundBank.GetCue("shoot");

            isWaveFinished = false;

            spellIcons = new List<Texture2D>();

            m_Camera = new GameClasses.Camera(game);

            m_Scenery = new GameObjects.Scenery(game);
            m_Player = new GameObjects.Player(game);
            m_Castle = new GameObjects.Fort(game);
            m_SpellHandler = new GameObjects.SpellHandler(game);
            m_EnemyHandler = new GameObjects.EnemyHandler(game);

            // Particle systems
            fireBallParticles = new FireParticleSystem(game, game.Content);
            slowEnemyParticles = new SlowParticleSystem(game, game.Content);
            poisonEnemyParticles = new PoisonParticleSystem(game, game.Content);
            magicMissilePartilces = new MagicMissileParticleSystem(game, game.Content);
            dirtPartilces = new DirtParticleSystem(game, game.Content);

            fpsCounterComponent = new global::MageDefender.HelperComponents.FrameRateCounter(game);
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            effectPostOutlineSilhouettes = Game.Content.Load<Effect>("Shaders\\OutLineSilhouettesShader");
            effectPostOutlineParticles = Game.Content.Load<Effect>("Shaders\\OutLineParticlesShader");
            effectFindEdges = Game.Content.Load<Effect>("Shaders\\SilhouettesBaseShader");

            // Particle systems
            fireBallParticles.Initialize();
            slowEnemyParticles.Initialize();
            poisonEnemyParticles.Initialize();
            magicMissilePartilces.Initialize();
            dirtPartilces.Initialize();


            fpsCounterComponent.Initialize();
            
            m_Camera.Initialize();
            m_Camera.Position = new Vector3(0 * cameraZoom, 1688.753f * cameraZoom, -2228.385f * cameraZoom);
            m_Camera.LookAt = new Vector3(0, 0, 20);
            this.Game.Services.AddService(typeof(Interfaces.ICamera), m_Camera);

            m_Castle.Initialize(m_Camera.ProjectionMatrix, m_Camera.ViewMatrix);
            this.Game.Services.AddService(typeof(Interfaces.IFort), m_Castle);

            m_Player.Initialize(m_Camera.ProjectionMatrix, m_Camera.ViewMatrix);
            this.Game.Services.AddService(typeof(Interfaces.IPlayer), m_Player);

            m_SpellHandler.Initialize(m_Camera.ProjectionMatrix, m_Camera.ViewMatrix);
            this.Game.Services.AddService(typeof(Interfaces.ISpellHandler), m_SpellHandler);

            m_EnemyHandler.Initialize(m_Camera.ProjectionMatrix, m_Camera.ViewMatrix);
            m_Scenery.Initialize(m_Camera.ProjectionMatrix, m_Camera.ViewMatrix);

            m_font = Game.Content.Load<SpriteFont>(@"Comic");
            m_fontLarge = Game.Content.Load<SpriteFont>(@"ComicLarge");

            StartNewWave();


            base.Initialize();
        }

        protected override void LoadContent()
        {
            PresentationParameters pp = Game.GraphicsDevice.PresentationParameters;
            renderTargetMainScene = new RenderTarget2D(Game.GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, 1, Game.GraphicsDevice.DisplayMode.Format);
            renderTargetStrippedScene = new RenderTarget2D(Game.GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, 1, Game.GraphicsDevice.DisplayMode.Format);
            renderTargetSilhouettesScene = new RenderTarget2D(Game.GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, 1, Game.GraphicsDevice.DisplayMode.Format);
            renderTargetFinalCompScene = new RenderTarget2D(Game.GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, 1, Game.GraphicsDevice.DisplayMode.Format);
            renderTargetParticlesOnlyScene = new RenderTarget2D(Game.GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, 1, Game.GraphicsDevice.DisplayMode.Format);

            spriteBatch = new SpriteBatch(GraphicsDevice);
            mdUITexture = Game.Content.Load<Texture2D>("Textures\\mdUI");
            mdUIBackTexture = Game.Content.Load<Texture2D>("Textures\\mdUI_back");
            blankTexture = Game.Content.Load<Texture2D>("Textures\\blank");
            bossUITexture = Game.Content.Load<Texture2D>("Textures\\bossHealthBar");
            waveCompleteTexture = Game.Content.Load<Texture2D>("Textures\\WaveCompleted");
            levelUpNotifier = Game.Content.Load<Texture2D>("Textures\\levelup");

            spellIcons.Add(Game.Content.Load<Texture2D>("Textures\\icon_fireball"));
            spellIcons.Add(Game.Content.Load<Texture2D>("Textures\\icon_slow"));
            spellIcons.Add(Game.Content.Load<Texture2D>("Textures\\icon_poison"));
            spellIcons.Add(Game.Content.Load<Texture2D>("Textures\\icon_MM"));
            spellIcons.Add(Game.Content.Load<Texture2D>("Textures\\icon_energyball"));
            spellIcons.Add(Game.Content.Load<Texture2D>("Textures\\icon_MM2"));
            spellIcons.Add( Game.Content.Load<Texture2D>("Textures\\icon_MM4"));

            base.LoadContent();
        }

        protected override void UnloadContent()
        {
            base.UnloadContent();
        }


        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            engine.Update();


            pressTimerPrimary -= gameTime.ElapsedGameTime.Milliseconds*2;
            pressTimerSecondary -= gameTime.ElapsedGameTime.Milliseconds;
            pressTimerSpellBrowse -= gameTime.ElapsedGameTime.Milliseconds;
            drinkPotionTimer -= gameTime.ElapsedGameTime.Milliseconds;

            GamePadState playerState = GamePad.GetState(m_Player.PlayerIndexSaved);
            KeyboardState keyboard = Keyboard.GetState();

            // Move camera
            m_Camera.PositionY -= playerState.ThumbSticks.Right.Y*10;
            if (keyboard.IsKeyDown(Keys.PageDown))
            {
                m_Camera.PositionY -= gameTime.ElapsedGameTime.Milliseconds;
            }
            if (keyboard.IsKeyDown(Keys.PageUp))
            {
                m_Camera.PositionY += gameTime.ElapsedGameTime.Milliseconds;
            }

            if (m_Camera.PositionY <= 400.0f)
                m_Camera.PositionY = 400.0f;

            if (m_Camera.PositionY >= 2000.0f)
                m_Camera.PositionY = 2000.0f;


            if (m_Castle.TheCastle.EnemiesInCurrentWave <= 0)
            {
                if (m_EnemyHandler.AllEnemiesDead)
                {
                    finishTimer -= gameTime.ElapsedGameTime.Milliseconds;
                    if (finishTimer <= 0)
                    {
                        isWaveFinished = true;
                        m_SpellHandler.ClearSpellList();
                        m_EnemyHandler.ClearEnemies();
                    }
                }
            }

            // Browse spells to the right
            if ((playerState.Buttons.RightShoulder == ButtonState.Pressed || keyboard.IsKeyDown(Keys.D)) && pressTimerSpellBrowse < 0)
            {
                int ss = (int)m_SpellHandler.SelectedSpellIndex;
                if (ss < m_SpellHandler.LearnedSpells.Count-1)
                {
                    m_SpellHandler.SelectedSpellIndex++;
                    m_SpellHandler.SelectedSpell = m_SpellHandler.LearnedSpells[m_SpellHandler.SelectedSpellIndex];
                }
                pressTimerSpellBrowse = 100;
            }

            // Browse spells to the left
            if ((playerState.Buttons.LeftShoulder == ButtonState.Pressed || keyboard.IsKeyDown(Keys.A)) && pressTimerSpellBrowse < 0)
            {
                int ss = (int)m_SpellHandler.SelectedSpellIndex;
                if (ss > 0)
                {
                    m_SpellHandler.SelectedSpellIndex--;
                    m_SpellHandler.SelectedSpell = m_SpellHandler.LearnedSpells[m_SpellHandler.SelectedSpellIndex];
                }
                pressTimerSpellBrowse = 100;
            }

            // Shoot primary spell
            if ((playerState.Buttons.X == ButtonState.Pressed || keyboard.IsKeyDown(Keys.LeftControl)) && pressTimerPrimary < 0)
            {
                int manaCost = m_SpellHandler.GetManaCost(GameObjects.SpellHandler.Spells.Fireball);
                if(m_Player.Mana >= manaCost)
                {
                    pressTimerPrimary = m_Player.CalculateSpellRecharge();
                    m_SpellHandler.AddSpell(m_Player.Position, GameObjects.SpellHandler.Spells.Fireball, Vector3.Zero);
                    m_Player.Mana -= manaCost;
                    m_Player.PlayAnimation(3);

                    shootCue = soundBank.GetCue("shoot");
                    if (!shootCue.IsPlaying)
                    {
                        shootCue.Play();
                    }
                }
            }

            // Shoot secondary spell
            if ((playerState.Buttons.A == ButtonState.Pressed || keyboard.IsKeyDown(Keys.LeftAlt)) && pressTimerSecondary < 0)
            {
                int manaCost = m_SpellHandler.GetManaCost(m_SpellHandler.SelectedSpell);
                if (m_Player.Mana >= manaCost)
                {
                    shootCue = soundBank.GetCue("shoot");
                    if (!shootCue.IsPlaying)
                    {
                        shootCue.Play();
                    }

                    pressTimerSecondary = m_Player.CalculateSpellRecharge();
                    if (m_EnemyHandler.EnemiesList.Count > 0)
                    {
                        Random rndEnemyOnScreen = new Random();
                        m_SpellHandler.AddSpell(m_Player.Position, m_SpellHandler.SelectedSpell, m_EnemyHandler.EnemiesList[rndEnemyOnScreen.Next(0, m_EnemyHandler.EnemiesList.Count)].Position);

                        // some special rules regarding some spells are defined under here
                        if (m_SpellHandler.SelectedSpell == global::MageDefender.GameObjects.SpellHandler.Spells.MagicMissileX2)
                        {
                            m_SpellHandler.AddSpell(m_Player.Position, m_SpellHandler.SelectedSpell, m_EnemyHandler.EnemiesList[rndEnemyOnScreen.Next(0, m_EnemyHandler.EnemiesList.Count)].Position);
                        }

                        if (m_SpellHandler.SelectedSpell == global::MageDefender.GameObjects.SpellHandler.Spells.MagicMissileX4)
                        {
                            m_SpellHandler.AddSpell(m_Player.Position, m_SpellHandler.SelectedSpell, m_EnemyHandler.EnemiesList[rndEnemyOnScreen.Next(0, m_EnemyHandler.EnemiesList.Count)].Position);
                            m_SpellHandler.AddSpell(m_Player.Position, m_SpellHandler.SelectedSpell, m_EnemyHandler.EnemiesList[rndEnemyOnScreen.Next(0, m_EnemyHandler.EnemiesList.Count)].Position);
                            m_SpellHandler.AddSpell(m_Player.Position, m_SpellHandler.SelectedSpell, m_EnemyHandler.EnemiesList[rndEnemyOnScreen.Next(0, m_EnemyHandler.EnemiesList.Count)].Position);
                        }

                    }
                    else
                    {
                        m_SpellHandler.AddSpell(m_Player.Position, m_SpellHandler.SelectedSpell, new Vector3(m_Player.Position.X,300,m_Player.Position.Z));
                    }

                    m_Player.Mana -= manaCost;
                    m_Player.PlayAnimation(3);
                }
            }

            // Drink a health potion
            if ((playerState.Buttons.B == ButtonState.Pressed ||  keyboard.IsKeyDown(Keys.W)) && drinkPotionTimer < 0)
            {
                if (m_Player.HealthPotions > 0)
                {
                    drinkPotionTimer = 1000;
                    m_Player.HealthPotions -= 1;
                    m_Player.Health += 50 + (m_Player.Strength*5);
                    if (m_Player.Health >= m_Player.MaxHealth)
                    {
                        m_Player.Health = m_Player.MaxHealth;
                    }
                }
            }

            // Drink a mana potion
            if ((playerState.Buttons.Y == ButtonState.Pressed || keyboard.IsKeyDown(Keys.S)) && drinkPotionTimer < 0)
            {
                if (m_Player.ManaPotions > 0)
                {
                    drinkPotionTimer = 1000;
                    m_Player.ManaPotions -= 1;
                    m_Player.Mana += 50 + (m_Player.Constitution * 5);
                    if (m_Player.Mana >= m_Player.MaxMana)
                    {
                        m_Player.Mana = m_Player.MaxMana;
                    }
                }
            }

            // TODO: Add your update code here
            m_Camera.Update(gameTime);

            m_Scenery.Update(gameTime, m_Camera.Position, m_Camera.ViewMatrix);
            m_Player.Update(gameTime, m_Camera.Position, m_Camera.ViewMatrix);
            m_Castle.Update(gameTime, m_Camera.Position, m_Camera.ViewMatrix);
            m_SpellHandler.Update(gameTime, m_Camera.Position, m_Camera.ViewMatrix, m_Camera.ProjectionMatrix);
            m_EnemyHandler.Update(gameTime, m_Camera.Position, m_Camera.ViewMatrix, m_Camera.ProjectionMatrix, m_SpellHandler, m_Player.Position);

            // Set proj and view matrix on particles
            fireBallParticles.SetCamera(m_Camera.ViewMatrix, m_Camera.ProjectionMatrix);
            slowEnemyParticles.SetCamera(m_Camera.ViewMatrix, m_Camera.ProjectionMatrix);
            poisonEnemyParticles.SetCamera(m_Camera.ViewMatrix, m_Camera.ProjectionMatrix);
            magicMissilePartilces.SetCamera(m_Camera.ViewMatrix, m_Camera.ProjectionMatrix);
            dirtPartilces.SetCamera(m_Camera.ViewMatrix, m_Camera.ProjectionMatrix);

            // Add particles
            foreach (GameClasses.Enemy e in m_EnemyHandler.EnemiesList)
            {
                if(e.IsDOT)
                {
                    for (int i = 0; i < 5; i++)
                    {
                        poisonEnemyParticles.AddParticle(new Vector3(e.PositionX * 0.008f, e.PositionY * 0.008f+2, e.PositionZ * 0.008f+2), Vector3.Zero);
                    }
                }
            }

            foreach (GameClasses.Spell s in m_SpellHandler.SpellList)
            {
                if (s.Type == GameObjects.SpellHandler.Spells.Fireball)
                {
                    for (int i = 0; i < 5; i++)
                    {
                        fireBallParticles.AddParticle(new Vector3(s.PositionX * 0.008f, s.PositionY * 0.008f, s.PositionZ * 0.008f), Vector3.Zero);
                    }
                }

                if (s.Type == GameObjects.SpellHandler.Spells.Slowball)
                {
                    for (int i = 0; i < 2; i++)
                    {
                        slowEnemyParticles.AddParticle(new Vector3(s.PositionX * 0.008f, s.PositionY * 0.008f, s.PositionZ * 0.008f), Vector3.Zero);
                    }
                }

                if (s.Type == GameObjects.SpellHandler.Spells.PoisonBall)
                {
                    for (int i = 0; i < 4; i++)
                    {
                        poisonEnemyParticles.AddParticle(new Vector3(s.PositionX * 0.008f, s.PositionY * 0.008f, s.PositionZ * 0.008f), Vector3.Zero);
                    }
                }

                if (s.Type == GameObjects.SpellHandler.Spells.MagicMissile)
                {
                    for (int i = 0; i < 5; i++)
                    {
                        magicMissilePartilces.AddParticle(new Vector3(s.PositionX * 0.008f, s.PositionY * 0.008f, s.PositionZ * 0.008f), Vector3.Zero);
                    }
                }

                if (s.Type == GameObjects.SpellHandler.Spells.EnergyBall)
                {
                    for (int i = 0; i < 5; i++)
                    {
                        magicMissilePartilces.AddParticle(new Vector3(s.PositionX * 0.008f, s.PositionY * 0.008f, s.PositionZ * 0.008f), Vector3.Zero);
                        fireBallParticles.AddParticle(new Vector3(s.PositionX * 0.008f, s.PositionY * 0.008f, s.PositionZ * 0.008f), Vector3.Zero);
                    }
                }
            }

            if (m_Player.Position.X < -1200)
            {
                for (int i = 0; i < 2; i++)
                {
                    magicMissilePartilces.AddParticle(new Vector3(m_Player.Position.X * 0.008f, m_Player.Position.Y * 0.008f, m_Player.Position.Z * 0.008f), Vector3.Zero);
                }
            }
            else
            {
                for (int i = 0; i < 1; i++)
                {
                    dirtPartilces.AddParticle(new Vector3(m_Player.Position.X * 0.008f, m_Player.Position.Y * 0.008f, m_Player.Position.Z * 0.008f), Vector3.Zero);
                }
            }

            // Update particles
            poisonEnemyParticles.Update(gameTime);
            slowEnemyParticles.Update(gameTime);
            fireBallParticles.Update(gameTime);
            magicMissilePartilces.Update(gameTime);
            dirtPartilces.Update(gameTime);
            
            fpsCounterComponent.Update(gameTime);

            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            int width = Game.GraphicsDevice.PresentationParameters.BackBufferWidth;
            int height = Game.GraphicsDevice.PresentationParameters.BackBufferHeight;

            ///////////////////////////////////
            // Render the scene to texture
            Game.GraphicsDevice.SetRenderTarget(0, renderTargetMainScene);
            Game.GraphicsDevice.Clear(Color.DarkSlateBlue);


            m_Scenery.DrawWithGround(gameTime);
            m_Castle.Draw(gameTime);

            m_EnemyHandler.DrawWithParticles(gameTime);
            m_SpellHandler.DrawWithParticles(gameTime);
            m_Player.Draw(gameTime);


            // render particles
            spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.SaveState);
            slowEnemyParticles.Draw(gameTime);
            poisonEnemyParticles.Draw(gameTime);
            fireBallParticles.Draw(gameTime);
            magicMissilePartilces.Draw(gameTime);
            dirtPartilces.Draw(gameTime);
            spriteBatch.End();

            Game.GraphicsDevice.SetRenderTarget(0, null);
            textureMainScene = renderTargetMainScene.GetTexture();


            ///////////////////////////////////////////////////////
            // Render a stripepd down version of the scene,
            // containing only items we want to have an outline around,
            Game.GraphicsDevice.SetRenderTarget(0, renderTargetStrippedScene);
            Game.GraphicsDevice.Clear(new Color(1.0f, 0.0f, 1.0f, 1.0f));

            m_Scenery.Draw(gameTime);
            m_EnemyHandler.Draw(gameTime);
            m_SpellHandler.Draw(gameTime);
            m_Player.Draw(gameTime);
            m_Castle.Draw(gameTime);

            Game.GraphicsDevice.SetRenderTarget(0, null);
            textureStrippedScene = renderTargetStrippedScene.GetTexture();

            ////////////////////////////////////////////////////////
            // Use shader to to create a texture containing two colors
            // one for non silhouettes and other for silhouettes
            Game.GraphicsDevice.SetRenderTarget(0, renderTargetSilhouettesScene);
            Game.GraphicsDevice.Clear(new Color(1.0f, 0.0f, 1.0f, 1.0f));

            spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.SaveState);
            {
                // Apply the post process shader
                effectFindEdges.Begin();
                {
                    effectFindEdges.CurrentTechnique.Passes[0].Begin();
                    {
                        spriteBatch.Draw(textureStrippedScene, new Rectangle(0, 0, width, height), Color.White);
                        effectFindEdges.CurrentTechnique.Passes[0].End();
                    }
                }
                effectFindEdges.End();
            }
            spriteBatch.End();

            Game.GraphicsDevice.SetRenderTarget(0, null);
            textureSilhouettesScene = renderTargetSilhouettesScene.GetTexture();


            ///////////////////////////////////////////
            // Render only the particles, we want to
            // make these have a different form for outlining
            Game.GraphicsDevice.SetRenderTarget(0, renderTargetParticlesOnlyScene);
            Game.GraphicsDevice.Clear(new Color(0.0f, 0.0f, 0.0f, 1.0f));

            // render particles
            spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.SaveState);
            m_SpellHandler.DrawParticlesOnly(gameTime);
            m_EnemyHandler.DrawParticlesOnly(gameTime);

            slowEnemyParticles.Draw(gameTime);
            poisonEnemyParticles.Draw(gameTime);
            fireBallParticles.Draw(gameTime);
            magicMissilePartilces.Draw(gameTime);
            dirtPartilces.Draw(gameTime);
            spriteBatch.End();


            Game.GraphicsDevice.SetRenderTarget(0, null);
            textureParticlesOnlyScene = renderTargetParticlesOnlyScene.GetTexture();


            ////////////////////////////////////////////////////
            // Final comp scene scene without particle outline
            Game.GraphicsDevice.SetRenderTarget(0, renderTargetFinalCompScene);
            Game.GraphicsDevice.Clear(new Color(0.0f, 0.0f, 0.0f, 0.0f));

            spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.SaveState);
            {
                // Apply the post process shader
                effectPostOutlineSilhouettes.Begin();
                {
                    effectPostOutlineSilhouettes.CurrentTechnique.Passes[0].Begin();
                    {
                        effectPostOutlineSilhouettes.Parameters["Thickness"].SetValue(0.05f);
                        effectPostOutlineSilhouettes.Parameters["Threshold"].SetValue(0.01f);
                        effectPostOutlineSilhouettes.Parameters["SiluetteMap"].SetValue(textureSilhouettesScene);

                        spriteBatch.Draw(textureMainScene, new Rectangle(0, 0, width, height), Color.White);
                        effectPostOutlineSilhouettes.CurrentTechnique.Passes[0].End();
                    }
                }
                effectPostOutlineSilhouettes.End();
            }
            spriteBatch.End();

            Game.GraphicsDevice.SetRenderTarget(0, null);
            textureFinalCompScene = renderTargetFinalCompScene.GetTexture();

            /////////////////////////////////
            // Assemble the scene
            Game.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.DarkSlateBlue, 1.0f, 0);

            // Render scene
            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
            {
                spriteBatch.Draw(textureFinalCompScene, new Rectangle(0, 0, width, height), Color.White);
            }
            spriteBatch.End();

            // Blend particle edges with scene
            GraphicsDevice.RenderState.AlphaTestEnable = true;
            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
            {
                
                //spriteBatch.Draw(textureFinalCompScene, new Rectangle(0, 0, width, height), Color.White);
                // Apply the post process shader
                effectPostOutlineParticles.Begin();
                {
                    effectPostOutlineParticles.CurrentTechnique.Passes[0].Begin();
                    {
                        effectPostOutlineParticles.Parameters["Thickness"].SetValue(0.3f);
                        effectPostOutlineParticles.Parameters["Threshold"].SetValue(0.1f);

                        spriteBatch.Draw(textureParticlesOnlyScene, new Rectangle(0, 0, width, height), Color.White);
                        effectPostOutlineParticles.CurrentTechnique.Passes[0].End();
                    }
                }
                effectPostOutlineParticles.End();
            }
            spriteBatch.End();


            // Render UI
            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
            //spriteBatch.DrawString(m_font, "Xp " + m_Player.Xp + " / " + m_Player.XpToNextLevel, new Vector2(0, 60), Color.Red);
            //spriteBatch.DrawString(m_font, "Level " + m_Player.Level, new Vector2(0, 80), Color.Red);
            //spriteBatch.DrawString(m_font, "Spell " + m_SpellHandler.SelectedSpell.ToString(), new Vector2(0, 140), Color.Red);
            //spriteBatch.DrawString(m_font, "Score " + m_Player.Score, new Vector2(0, 160), Color.Red);
            //spriteBatch.DrawString(m_font, "Ap " + m_Player.Ap, new Vector2(0, 180), Color.Red);
            //spriteBatch.DrawString(m_font, "Mana potions " + m_Player.ManaPotions, new Vector2(0, 200), Color.Red);
            //spriteBatch.DrawString(m_font, "Health potions " + m_Player.HealthPotions, new Vector2(0, 220), Color.Red);

            
            //spriteBatch.DrawString(m_font, "Level " + m_Castle.TheCastle.Level, new Vector2(900, 20), Color.Gold);
            //spriteBatch.DrawString(m_font, "Enemies " + m_Castle.TheCastle.EnemiesInCurrentWave, new Vector2(900, 40), Color.Gold);
            //spriteBatch.DrawString(m_font, "Wave " + m_Castle.TheCastle.Wave, new Vector2(900, 60), Color.Gold);

            spriteBatch.Draw(mdUIBackTexture, new Rectangle(0, 0, width, height), Color.White);

            // Draw healthbar
            float healthLeft = ((float)m_Player.Health / (float)m_Player.MaxHealth) * ((float)width * 0.16f);
            spriteBatch.Draw(blankTexture, new Rectangle(Convert.ToInt32(width * 0.047f), Convert.ToInt32(height * 0.07f), (int)healthLeft, Convert.ToInt32(height * 0.0222f)), Color.Red);

            float manaLeft = ((float)m_Player.Mana / (float)m_Player.MaxMana) * ((float)width * 0.16f);
            spriteBatch.Draw(blankTexture, new Rectangle(Convert.ToInt32(width * 0.050f), Convert.ToInt32(height * 0.11f), (int)manaLeft, Convert.ToInt32(height * 0.0222f)), Color.Blue);

            float castleHealth = ((1.0f-((float)m_Player.Xp / (float)m_Player.XpToNextLevel))) * ((float)height * 0.06f);
            spriteBatch.Draw(blankTexture, new Rectangle(Convert.ToInt32(width * 0.232f), Convert.ToInt32(height * 0.07f), Convert.ToInt32(height * 0.02f), (int)castleHealth), new Color(95,68,40,255));

            if (m_Castle.TheCastle.IsCurrentWaveABoss)
            {
                if (m_EnemyHandler.SpawnEnemyTypes.Count >= 1)
                {
                    if (m_EnemyHandler.EnemiesList.Count >= 1)
                    {
                        spriteBatch.Draw(bossUITexture, new Rectangle(0, 0, width, height), new Color(new Vector4(1, 1, 1, 1)));
                        //spriteBatch.DrawString(m_font, "Boss HP " + m_EnemyHandler.EnemiesList[0].Health, new Vector2(900, 80), Color.Black);
                        float bossHealth = ((float)m_EnemyHandler.EnemiesList[0].Health / (float)m_EnemyHandler.EnemiesList[0].MaxHealth) * ((float)width * 0.435f);
                        spriteBatch.Draw(blankTexture, new Rectangle(Convert.ToInt32(width * 0.267f), Convert.ToInt32(height * 0.1055f), (int)bossHealth, Convert.ToInt32(height * 0.0222f)), Color.Green);
                        spriteBatch.DrawString(m_font, "Boss: " + m_EnemyHandler.EnemiesList[0].Name, new Vector2(Convert.ToInt32(width * 0.267f), Convert.ToInt32(height * 0.13f)), Color.Gold);
                    }
                }
            }

            spriteBatch.Draw(mdUITexture, new Rectangle(0, 0, width, height), Color.White);

            spriteBatch.DrawString(m_font, "" + (m_Castle.TheCastle.Level) + "/6", new Vector2(Convert.ToInt32(width * 0.142f), Convert.ToInt32(height * 0.185)), Color.Black);
            spriteBatch.DrawString(m_font, "" + (m_Castle.TheCastle.Level) + "/6", new Vector2(Convert.ToInt32(width * 0.14f), Convert.ToInt32(height * 0.18)), Color.White);

            spriteBatch.DrawString(m_font, "" + (m_Player.Level), new Vector2(Convert.ToInt32(width * 0.245f), Convert.ToInt32(height * 0.07)), Color.Black);
            spriteBatch.DrawString(m_font, "" + (m_Player.Level), new Vector2(Convert.ToInt32(width * 0.247f), Convert.ToInt32(height * 0.065)), Color.White);

            spriteBatch.DrawString(m_font, "" + (m_Castle.TheCastle.Level), new Vector2(Convert.ToInt32(width * 0.835f), Convert.ToInt32(height * 0.06)), Color.Black);
            spriteBatch.DrawString(m_font, "" + (m_Castle.TheCastle.Level), new Vector2(Convert.ToInt32(width * 0.837f), Convert.ToInt32(height * 0.055)), Color.White);

            spriteBatch.DrawString(m_font, "" + (m_Castle.TheCastle.Wave), new Vector2(Convert.ToInt32(width * 0.835f), Convert.ToInt32(height * 0.1)), Color.Black);
            spriteBatch.DrawString(m_font, "" + (m_Castle.TheCastle.Wave), new Vector2(Convert.ToInt32(width * 0.837f), Convert.ToInt32(height * 0.095)), Color.White);

            spriteBatch.DrawString(m_fontLarge, "" + (m_Castle.TheCastle.EnemiesInCurrentWave), new Vector2(Convert.ToInt32(width * 0.855f), Convert.ToInt32(height * 0.195)), Color.Black);
            spriteBatch.DrawString(m_fontLarge, "" + (m_Castle.TheCastle.EnemiesInCurrentWave), new Vector2(Convert.ToInt32(width * 0.857f), Convert.ToInt32(height * 0.190)), Color.White);

            spriteBatch.DrawString(m_fontLarge, "" + (m_Player.ManaPotions), new Vector2(Convert.ToInt32(width * 0.875f), Convert.ToInt32(height * 0.86)), Color.Black);
            spriteBatch.DrawString(m_fontLarge, "" + (m_Player.ManaPotions), new Vector2(Convert.ToInt32(width * 0.877f), Convert.ToInt32(height * 0.855)), Color.White);

            spriteBatch.DrawString(m_fontLarge, "" + (m_Player.HealthPotions), new Vector2(Convert.ToInt32(width * 0.095f), Convert.ToInt32(height * 0.86)), Color.Black);
            spriteBatch.DrawString(m_fontLarge, "" + (m_Player.HealthPotions), new Vector2(Convert.ToInt32(width * 0.097f), Convert.ToInt32(height * 0.855)), Color.White);


            switch (m_SpellHandler.SelectedSpell)
            {
                case GameObjects.SpellHandler.Spells.Fireball:
                {
                    spriteBatch.Draw(spellIcons[0], new Rectangle(Convert.ToInt32(width * 0.050f), Convert.ToInt32(height * 0.18f), Convert.ToInt32(width * 0.025f * 1.5f), Convert.ToInt32(height * 0.0444f * 1.5f)), Color.White);
                    break;
                }
                case GameObjects.SpellHandler.Spells.Slowball:
                {
                    spriteBatch.Draw(spellIcons[1], new Rectangle(Convert.ToInt32(width * 0.050f), Convert.ToInt32(height * 0.18f), Convert.ToInt32(width * 0.025f * 1.5f), Convert.ToInt32(height * 0.0444f * 1.5f)), Color.White);
                    break;
                }
                case GameObjects.SpellHandler.Spells.PoisonBall:
                {
                    spriteBatch.Draw(spellIcons[2], new Rectangle(Convert.ToInt32(width * 0.050f), Convert.ToInt32(height * 0.18f), Convert.ToInt32(width * 0.025f * 1.5f), Convert.ToInt32(height * 0.0444f * 1.5f)), Color.White);
                    break;
                }
                case GameObjects.SpellHandler.Spells.MagicMissile:
                {
                    spriteBatch.Draw(spellIcons[3], new Rectangle(Convert.ToInt32(width * 0.050f), Convert.ToInt32(height * 0.18f), Convert.ToInt32(width * 0.025f * 1.5f), Convert.ToInt32(height * 0.0444f * 1.5f)), Color.White);
                    break;
                }
                case GameObjects.SpellHandler.Spells.EnergyBall:
                {
                    spriteBatch.Draw(spellIcons[4], new Rectangle(Convert.ToInt32(width * 0.050f), Convert.ToInt32(height * 0.18f), Convert.ToInt32(width * 0.025f * 1.5f), Convert.ToInt32(height * 0.0444f * 1.5f)), Color.White);
                    break;
                }
                case GameObjects.SpellHandler.Spells.MagicMissileX2:
                {
                    spriteBatch.Draw(spellIcons[5], new Rectangle(Convert.ToInt32(width * 0.050f), Convert.ToInt32(height * 0.18f), Convert.ToInt32(width * 0.025f * 1.5f), Convert.ToInt32(height * 0.0444f * 1.5f)), Color.White);
                    break;
                }
                case GameObjects.SpellHandler.Spells.MagicMissileX4:
                {
                    spriteBatch.Draw(spellIcons[6], new Rectangle(Convert.ToInt32(width * 0.050f), Convert.ToInt32(height * 0.18f), Convert.ToInt32(width * 0.025f * 1.5f), Convert.ToInt32(height * 0.0444f * 1.5f)), Color.White);
                    break;
                }
            }

            if (m_Castle.TheCastle.EnemiesInCurrentWave <= 0)
            {
                if (m_EnemyHandler.AllEnemiesDead)
                {
                    spriteBatch.Draw(waveCompleteTexture, new Rectangle(0, 0, width, height), Color.White);
                }
            }

            if (m_Player.DisplayLevelUpTimer > 0)
            {
                spriteBatch.Draw(levelUpNotifier, new Rectangle(0, 0, width, height), new Color(1.0f, 1.0f, 1.0f, (m_Player.DisplayLevelUpTimer/3000.0f)));
            }

            spriteBatch.End();


            // For debugging only
            //fpsCounterComponent.Draw(gameTime);

            base.Draw(gameTime);
        }
    }
}
